﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using Styx.CommonBot.Routines;
using Styx;
using Styx.WoWInternals.WoWObjects;
using Styx.Common;
using Styx.CommonBot;
using Styx.TreeSharp;
using Action = Styx.TreeSharp.Action;
using Styx.WoWInternals;
using System.Diagnostics;

/*
 * Thanks to falldown, used his Bowman as a basis for coding, check out his work here: http://www.thebuddyforum.com/honorbuddy-forum/combat-routines/hunter/68054-beast-master-lazyraider.html
 * Also Thanks to the Singular Team & HandNavi for the TimeToLife Code I'm using
 * 
 * This CC only Supports PVE Survivial Behavior!
 */

namespace PVEDPS_Hunter
{
    public class PVEDPS : CombatRoutine
    {
        #region variables - later to be set in a GUI
        //private bool varX= true;            //dat cmt
        
        private int varAdds= 4;             //AoE on X Adds
        private bool varMendPet= true;      //set true/false to heal or not heal pet, pet will be healed once below 70% and no mend aura active      
        private bool varTrinket1= true;     //set true/false to use First Trinket (Trinkets will be used on CD, not only Boss!
        private bool varTrinket2= false;    //set true/false to use Second Trinket (Trinkets will be used on CD, not only Boss!
        //private bool softTargetHelp= true;  //set true/false to enable/disable "soft Target help" - means CC will find a target if we have none. (target in combat within 40yds with most hp)
        #endregion

        #region overrides / init
        public override WoWClass Class { get { return WoWClass.Hunter; } }
        public static readonly Version version = new Version(1, 1, 0, 8);
        public override string Name { get { return "PVEDPS Hunter " + version; } }
        private static LocalPlayer Me { get { return StyxWoW.Me; } }
        private delegate WoWUnit UnitSelection(object unit);
        public override bool WantButton { get { return true; } }
        public override void OnButtonPress()
        {
            write("no config needed");
        }
        public override void Initialize()
        {
            write("{0}", Name);
            write("Level {0} {3} {1} {2}", Me.Level, Me.Race, Me.Class, Me.Specialization);
            write("Make sure to use CombatBot / RaidBot / Lazyraider / Tyrael");

            if (Class != WoWClass.Hunter)
                write("## YOU ARE NO HUNTER! THIS CC WILL NOT WORK FOR YOU! ###");

        }
        #endregion

        #region stupid helpers       
        private bool FeignDeath()
        {
            {
                if (Me.HasAura("Feign Death"))
                    return true;
            }
            return false;
        }
        private static string safeName(WoWUnit unit)
        {
            if (unit != null)
            {
                return (unit.Name == Me.Name) ? "Myself" : unit.Name;
            }
            return "No Target";
        }
        private bool SelfControl(WoWUnit unit)
        {
            if (Me.GotTarget && (unit.HasAura("Freezing Trap") || unit.HasAura("Wyvern Sting") || unit.HasAura("Bad Manner") || unit.HasAura("Scatter Shot")))
                return true;

            else return false;
        }
        #endregion

        #region logging
        public static void write(string msg, params object[] args)
        {
            if (msg != null)
            {
                Logging.Write(Colors.Crimson, msg, args);
            }
        }
        #endregion

        #region target checks
        private bool TargetIsBoss()
        {
            if (Me.CurrentTarget.Name.Contains("Dummy") ||                                                                      //Boss= Dummy
                Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.WorldBoss ||                                         //or= Boss
                Me.CurrentTarget.MaxHealth >= 20000000                                                                           //or more than 20mil hp
                )
                return true;

            return false;
        }
        private bool TargetIsValid()
        {
            if (Me.GotTarget && Me.CurrentTarget.IsAlive && Me.CurrentTarget.Attackable && Me.CurrentTarget.CanSelect && !Me.CurrentTarget.IsFriendly)
                return true;

            return false;
        }
        private bool TargetDistance()
        {
            return TargetDistance(40);
        }
        private bool TargetDistance(int dist)
        {
            if (TargetIsValid() && Me.CurrentTarget.Distance <= dist)
                return true;

            return false;
        }
        #endregion

        #region cast etc
        private static bool CanCast(string spell)
        {
            return CanCast(spell, Me.CurrentTarget);
        }
        private static bool CanCast(string spell, WoWUnit target)
        {
            if (SpellManager.HasSpell(spell) && SpellManager.Spells[spell].CooldownTimeLeft.TotalMilliseconds < 200 && Me.CurrentFocus >= SpellManager.Spells[spell].PowerCost && !Me.IsChanneling && (!Me.IsCasting || Me.CurrentCastTimeLeft.TotalMilliseconds < 350))
            {
                //SpellManager.Cast(spell, target);
                return true;
            }

            return false;
        }
        private static TimeSpan SpellCooldown(string spell)
        {
            return SpellManager.HasSpell(spell) ? SpellManager.Spells[spell].CooldownTimeLeft : TimeSpan.MaxValue;
        }
        private static Composite CastSpell(string spell, CanRunDecoratorDelegate cond, string label)
        {
            return CastSpell(spell, ret => Me.CurrentTarget, cond, label);
        }
        private static Composite CastSpell(string spell, UnitSelection onUnit, CanRunDecoratorDelegate cond, string label)
        {
            return (
                new Decorator(delegate(object a)
                {
                    if (!cond(a))
                        return false;
                    if (!CanCast(spell, onUnit(a)))
                        return false;
                    return onUnit(a) != null;
                },
                    new Sequence(
                        new Action(a => write("[Casting] {0} on {1}", label, safeName(onUnit(a)))),
                        new Action(a => SpellManager.Cast(spell, onUnit(a))))
                    )
            );
        }
        private static Composite CastSelfSpell(string spell, CanRunDecoratorDelegate cond, string label)
        {
            return CastSpell(spell, ret => Me, cond, label);
        }
        private static Composite CastOnTarget(string spell, UnitSelection onUnit, CanRunDecoratorDelegate cond, string label)
        {
            return new Decorator(
                delegate(object a)
                {
                    if (!cond(a))
                        return false;
                    if (!CanCast(spell, onUnit(a)))
                        return false;

                    return onUnit(a) != null;
                },
            new Sequence(
                new Action(a => write("[Casting] {0} on {1}", label, safeName(onUnit(a)))),
                new Action(a => SpellManager.Cast(spell, onUnit(a)))));
        }
        private static Composite CastOnUnitLocation(string spell, UnitSelection onUnit, CanRunDecoratorDelegate cond, string label)
        {
            return (
                new Decorator(delegate(object a)
                {
                    if (!cond(a))
                        return false;
                    return onUnit != null && CanCast(spell, onUnit(a));
                },
                    new Sequence(
                    new Action(a => write("[Casting at Location] {0} ", label)),
                    new Action(a => SpellManager.Cast(spell)),
                    new Action(ret => SpellManager.ClickRemoteLocation(onUnit(ret).Location)))));
        }
        #endregion

        #region items etc
        private static bool CanUseEquippedItem(WoWItem item)
        {
            // Check for engineering tinkers!
            string itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
                return false;

            return item.Usable && item.Cooldown <= 0;
        }
        private static void UseItem(WoWItem item)
        {
            write("[UseItem] " + item.Name);
            item.Use();
        }
        public static Composite UseEquippedItem(uint slot)
        {
            return new PrioritySelector(
                ctx => StyxWoW.Me.Inventory.GetItemBySlot(slot),
                new Decorator(
                    ctx => ctx != null && CanUseEquippedItem((WoWItem)ctx),
                    new Action(ctx => UseItem((WoWItem)ctx))));

        }
        public static Composite UseBagItem(string name, CanRunDecoratorDelegate cond, string label)
        {
            WoWItem item = null;
            return new Decorator(
                delegate(object a)
                {
                    if (!cond(a))
                        return false;
                    item = Me.BagItems.FirstOrDefault(x => x.Name == name && x.Usable && x.Cooldown <= 0);
                    return item != null;
                },
            new Sequence(
                new Action(a => write(" [BagItem] {0} ", label)),
                new Action(a => item.UseContainerItem())));
        }
        #endregion

        #region Adds
        private int Adds
        {
            get
            {
                int count = 0;
                foreach (WoWUnit u in ObjectManager.GetObjectsOfType<WoWUnit>(true, true))
                {
                    if (Me.GotTarget
                        && u.IsAlive
                        && u.Guid != Me.Guid
                        && !u.IsFriendly
                        && u.IsHostile
                        && u.Attackable
                        && !u.IsTotem
                        && !u.IsCritter
                        && !u.IsNonCombatPet
                        && u.GotTarget
                        && (u.Location.Distance(Me.CurrentTarget.Location) <= 10 || u.Location.Distance2D(Me.CurrentTarget.Location) <= 10))
                    {
                        count++;
                    }
                }
                return count;
            }
        }
        #endregion

        #region Buff / Debuff checks
        private int MyDebuffTime(String SpellName, WoWUnit unit)    //Used for checking how the time left on "my" debuff
        {
            {
                if (unit.HasAura(SpellName))
                {
                    var auras = unit.GetAllAuras();
                    foreach (var a in auras)
                    {
                        if (a.Name == SpellName && a.CreatorGuid == Me.Guid)
                        {
                            return a.TimeLeft.Seconds;
                        }
                    }
                }
            }
            return 0;
        }
        private int DebuffTime(String SpellName, WoWUnit unit)      //Used for checking debuff timers
        {
            {
                if (unit.HasAura(SpellName))
                {
                    var auras = unit.GetAllAuras();
                    foreach (var b in auras)
                    {
                        if (b.Name == SpellName)
                        {
                            return b.TimeLeft.Seconds;
                        }
                    }
                }
            }
            return 0;
        }
        private bool IsMyAuraActive(WoWUnit Who, String What)       //Used for checking auras that has no time
        {
            {
                return Who.GetAllAuras().Where(p => p.CreatorGuid == Me.Guid && p.Name == What).FirstOrDefault() != null;
            }
        }
        #endregion

        #region TimeToDeath by HandNavi     
        /* Time to death code was made by HandNavi for the Junglebook CC, all credit goes to him! */
        private static uint _firstLife;
        private static uint _firstLifeMax;
        private static Stopwatch deathTimer = new Stopwatch();
        private static uint _currentLife;
        private static ulong _guid;
        private static long CalculateTimeToDeath(WoWUnit target)
        {
            if (target.Name.Contains("Training Dummy"))
            {
                return 111;
            }
            if (target.CurrentHealth == 0 || target.IsDead || !target.IsValid || !target.IsAlive)
            {
                return 0;
            }
            //Fill variables on new target or on target switch, this will lose all calculations from last target
            if (_guid != target.Guid || (_guid == target.Guid && target.CurrentHealth == _firstLifeMax))
            {
                _guid = target.Guid;
                _firstLife = target.CurrentHealth;
                _firstLifeMax = target.MaxHealth;
                deathTimer.Restart();
            }
            _currentLife = target.CurrentHealth;
            int timeDiff = deathTimer.Elapsed.Seconds;
            uint hpDiff = _firstLife - _currentLife;
            if (hpDiff > 0)
            {
                long fullTime = timeDiff * _firstLifeMax / hpDiff;
                long pastFirstTime = (_firstLifeMax - _firstLife) * timeDiff / hpDiff;
                long timeToDie = fullTime - pastFirstTime - timeDiff;

                if (timeToDie < 1) timeToDie = 1;
                return timeToDie;
            }
            if (hpDiff <= 0)
            {
                // Target was healed, reset to initial values
                _guid = target.Guid;
                _firstLife = target.CurrentHealth;
                _firstLifeMax = target.MaxHealth;
                deathTimer.Restart();
                return -1;
            }
            // Target is at full health
            if (_currentLife == _firstLifeMax)
            {
                return -1;
            }
            // No damage done, nothing to calculate
            return -1;
        }
        #endregion

        #region Pet Handler
        private static Stopwatch ReviveTimer = new Stopwatch();
        private static Composite RevivePet(CanRunDecoratorDelegate cond, string label)
        {
            return RevivePet(ret => Me, cond, label);
        }
        private static Composite RevivePet(UnitSelection onUnit, CanRunDecoratorDelegate cond, string label)
        {
            return (
                new Decorator(delegate(object a)
                {
                    if (!cond(a))
                        return false;
                    if (!CanCast("Revive Pet", onUnit(a)))
                        return false;
                    return onUnit(a) != null;
                },
                    new Sequence(
                        new Action(a => ReviveTimer.Start()),
                        new Action(a => write("[Casting] {0} on {1}", label, safeName(onUnit(a)))),
                        new Action(a => SpellManager.Cast("Revive Pet", onUnit(a))))));
        }
        private static Composite CallPet(string spellName, CanRunDecoratorDelegate cond, string label)
        {
            return CallPet(spellName, ret => Me, cond, label);
        }
        private static Composite CallPet(string spellName, UnitSelection onUnit, CanRunDecoratorDelegate cond, string label)
        {
            return (
                new Decorator(delegate(object a)
                {
                    if (!cond(a))
                        return false;
                    if (!CanCast(spellName, onUnit(a)))
                        return false;
                    return onUnit(a) != null;
                },
                    new Sequence(
                        new Action(a => ReviveTimer.Reset()),
                        new Action(a => write("[Casting] {0} on {1}", label, safeName(onUnit(a)))),
                        new Action(a => SpellManager.Cast(spellName, onUnit(a))))));
        }
        
        #endregion

        #region Rotationswitch
        private Composite RotationBoss(CanRunDecoratorDelegate cond)
        {
            return (
                new Decorator(delegate(object a)
                {
                    if (!cond(a))
                        return false;
                    return true;
                },
                    new PrioritySelector(
                        //===============================================================================================
                        //== Cooldowns ==================================================================================

                        //Rapid Fire
                        CastSpell("Rapid Fire", ret => CalculateTimeToDeath(Me.CurrentTarget) > 10, "Rapid Fire"),

                        //Racials
                        new Decorator(ret => Me.Race == WoWRace.Troll && !SpellManager.Spells["Berserking"].Cooldown && CalculateTimeToDeath(Me.CurrentTarget) > 4,
                            new Action(delegate
                            {
                                Lua.DoString("RunMacroText('/Cast Berserking');");
                                Logging.Write(Colors.Lime, "[Racial] HULK SMASH (Berserking)");
                                return RunStatus.Failure;
                            }
                            )
                        ),
                        new Decorator(ret => Me.Race == WoWRace.Orc && !SpellManager.Spells["Blood Fury"].Cooldown && CalculateTimeToDeath(Me.CurrentTarget) > 4,
                            new Action(delegate
                            {
                                Lua.DoString("RunMacroText('/Cast Blood Fury');");
                                Logging.Write(Colors.Lime, "[Racial] HULK SMASH (Blood Fury)");
                                return RunStatus.Failure;
                            }
                            )
                        ),

                        //Trinkets
                        new Decorator(ret => varTrinket1 && Me.Inventory.Equipped.Trinket1 != null && Me.Inventory.Equipped.Trinket1.Cooldown <= 0 && Me.Inventory.Equipped.Trinket1.Usable,
                            new Action(delegate
                            {
                                Lua.DoString("RunMacroText('/use 13');");
                                {
                                    Logging.Write(Colors.Aquamarine, "[Trinket] {0}", Me.Inventory.Equipped.Trinket1.Name);
                                }
                                return RunStatus.Failure;
                            }
                            )
                        ),
                        new Decorator(ret => varTrinket2 && Me.Inventory.Equipped.Trinket2 != null && Me.Inventory.Equipped.Trinket2.Cooldown <= 0 && Me.Inventory.Equipped.Trinket2.Usable,
                            new Action(delegate
                            {
                                Lua.DoString("RunMacroText('/use 14');");
                                {
                                    Logging.Write(Colors.Aquamarine, "[Trinket] {0}", Me.Inventory.Equipped.Trinket2.Name);
                                }
                                return RunStatus.Failure;
                            }
                            )
                        ),

                        //Lifeblood
                        CastSelfSpell("Lifeblood", ret => CalculateTimeToDeath(Me.CurrentTarget) > 10, "Lifeblood (Herbalism)"),

                        //Stampede
                        CastSpell("Stampede", ret => CalculateTimeToDeath(Me.CurrentTarget) > 15, "Stampede"),

                        //================================================================================================
                        //== Thrill of the Hunt ==========================================================================
                        CastSpell("Arcane Shot", ret => Me.ActiveAuras.ContainsKey("Thrill of the Hunt"), "Arcane Shot (TotH)"),

                        //===============================================================================================
                        //== Tier-4-5-6 ==================================================================================

                        //Tier-4-Ability on cooldown.
                        CastSpell("Fervor", ret => SpellManager.HasSpell("Fervor") && !Me.HasAura(56453) && Me.CurrentFocus < 40 && CalculateTimeToDeath(Me.CurrentTarget) >= 4, "Fervor"),
                        CastSpell("Dire Beast", ret => SpellManager.HasSpell("Dire Beast") && !Me.HasAura(56453) && CalculateTimeToDeath(Me.CurrentTarget) >= 1, "Dire Beast"),

                        //Tier-5-Ability
                        CastSpell("A Murder of Crows", ret => SpellManager.HasSpell("A Murder of Crows") && CalculateTimeToDeath(Me.CurrentTarget) >= 15, "A Murder of Crows"),
                        CastSpell("Blink Strike", ret => SpellManager.HasSpell("Blink Strike") && CalculateTimeToDeath(Me.CurrentTarget) >= 1, "Blink Strike"),
                        CastSpell("Lynx Rush", ret => SpellManager.HasSpell("Lynx Rush") && CalculateTimeToDeath(Me.CurrentTarget) >= 3, "Lynx Rush"),

                        //Tier-6-Ability on cooldown. Barrage is channeled and cannot cast while moving, so only use if we stand!
                        CastSpell("Glaive Toss", ret => SpellManager.HasSpell("Glaive Toss") && !Me.HasAura(56453) && CalculateTimeToDeath(Me.CurrentTarget) >= 1, "Glaive Toss"),
                        CastSpell("Powershot", ret => SpellManager.HasSpell("Powershot") && !Me.HasAura(56453) && CalculateTimeToDeath(Me.CurrentTarget) >= 5, "Powershot"),
                        CastSpell("Barrage", ret => SpellManager.HasSpell("Barrage") && !Me.HasAura(56453) && !Me.IsMoving && CalculateTimeToDeath(Me.CurrentTarget) >= 3, "Barrage"),

                        //===============================================================================================
                        //== Normal Attacks =============================================================================

                        //Kill Shot when target is below 20% Health.
                        CastSpell("Kill Shot", ret => Me.CurrentTarget.HealthPercent < 20, "Kill Shot"),

                        //Serpent Sting Apply once. Refresh with Cobra Shot.
                        CastSpell("Serpent Sting", ret => !Me.HasAura(56453) && CalculateTimeToDeath(Me.CurrentTarget) >= 15 && (!IsMyAuraActive(Me.CurrentTarget, "Serpent Sting") || MyDebuffTime("Serpent Sting", Me.CurrentTarget) < 2), "Serpent Sting"),

                        //Explosive Shot on cooldown. Cast multiple with Lock and Load.
                        CastSpell("Explosive Shot", ret => SpellManager.HasSpell("Explosive Shot") && (Me.CurrentFocus >= SpellManager.Spells["Explosive Shot"].PowerCost || Me.HasAura(56453)) && (!IsMyAuraActive(Me.CurrentTarget, "Explosive Shot") || MyDebuffTime("Explosive Shot", Me.CurrentTarget) < 1), "Explosive Shot"),

                        //Black Arrow on cooldown. / Explosive Trap on 4+ mobs
                        CastSpell("Black Arrow", ret => SpellManager.HasSpell("Black Arrow") && Me.CurrentFocus >= SpellManager.Spells["Black Arrow"].PowerCost && (!IsMyAuraActive(Me.CurrentTarget, "Black Arrow") || MyDebuffTime("Black Arrow", Me.CurrentTarget) < 1) && Adds < 4, "Black Arrow"),

                        //nothing else to do, cobra bugged - use steady to cast cobra...
                        CastSpell("Steady Shot", ret => (!Me.HasAura(56453) || MyDebuffTime("Explosive Shot", Me.CurrentTarget) > 1) && ((SpellManager.Spells["Black Arrow"].CooldownTimeLeft.Seconds > 1 && Me.FocusPercent < 72) || (SpellManager.Spells["Black Arrow"].CooldownTimeLeft.Seconds < 1 && Me.CurrentFocus < 35)), "Cobra Shot"),
                        CastSpell("Arcane Shot", ret => !Me.HasAura(56453) && Me.FocusPercent > 62 && !CanCast("A Murder of Crows"), "Arcane Shot, Focus Dump (" + Me.FocusPercent + ")")
                    )
                )
            );
        }
        private Composite RotationAdds(CanRunDecoratorDelegate cond)
        {
            return (
                new Decorator(delegate(object a)
                {
                    if (!cond(a))
                        return false;
                    return true;
                },
                    new PrioritySelector(
                        //===============================================================================================
                        //== Cooldowns ==================================================================================

                        //Racials
                        new Decorator(ret => Me.Race == WoWRace.Troll && !SpellManager.Spells["Berserking"].Cooldown && CalculateTimeToDeath(Me.CurrentTarget) > 4,
                            new Action(delegate
                            {
                                Lua.DoString("RunMacroText('/Cast Berserking');");
                                Logging.Write(Colors.Lime, "[Racial] HULK SMASH (Berserking)");
                                return RunStatus.Failure;
                            }
                            )
                        ),
                        new Decorator(ret => Me.Race == WoWRace.Orc && !SpellManager.Spells["Blood Fury"].Cooldown && CalculateTimeToDeath(Me.CurrentTarget) > 4,
                            new Action(delegate
                            {
                                Lua.DoString("RunMacroText('/Cast Blood Fury');");
                                Logging.Write(Colors.Lime, "[Racial] HULK SMASH (Blood Fury)");
                                return RunStatus.Failure;
                            }
                            )
                        ),

                        //Trinkets
                        new Decorator(ret => varTrinket1 && Me.Inventory.Equipped.Trinket1 != null && Me.Inventory.Equipped.Trinket1.Cooldown <= 0 && Me.Inventory.Equipped.Trinket1.Usable,
                            new Action(delegate
                            {
                                Lua.DoString("RunMacroText('/use 13');");
                                {
                                    Logging.Write(Colors.Aquamarine, "[Trinket] {0}", Me.Inventory.Equipped.Trinket1.Name);
                                }
                                return RunStatus.Failure;
                            }
                            )
                        ),
                        new Decorator(ret => varTrinket2 && Me.Inventory.Equipped.Trinket2 != null && Me.Inventory.Equipped.Trinket2.Cooldown <= 0 && Me.Inventory.Equipped.Trinket2.Usable,
                            new Action(delegate
                            {
                                Lua.DoString("RunMacroText('/use 14');");
                                {
                                    Logging.Write(Colors.Aquamarine, "[Trinket] {0}", Me.Inventory.Equipped.Trinket2.Name);
                                }
                                return RunStatus.Failure;
                            }
                            )
                        ),

                        //================================================================================================
                        //== Thrill of the Hunt ==========================================================================
                        CastSpell("Multi-Shot", ret => Me.CurrentFocus > 20 && Me.ActiveAuras.ContainsKey("Thrill of the Hunt"), "Multi-Shot (TotH)"),
                        //CastSpell("Arcane Shot", ret => Me.CurrentFocus < 13 && Me.ActiveAuras.ContainsKey("Thrill of the Hunt"), "Arcane Shot (TotH)"),

                        //================================================================================================
                        //== Tier-4-5-6 ==================================================================================

                        //Tier-4-Ability on cooldown.
                        CastSpell("Fervor", ret => SpellManager.HasSpell("Fervor") && !Me.HasAura(56453) && Me.CurrentFocus < 40, "Fervor"),
                        CastSpell("Dire Beast", ret => SpellManager.HasSpell("Dire Beast") && !Me.HasAura(56453), "Dire Beast"),

                        //Tier-5-Ability
                        //CastSpell("A Murder of Crows", ret => SpellManager.HasSpell("A Murder of Crows") && CalculateTimeToDeath(Me.CurrentTarget) >= 15, "A Murder of Crows"),
                        CastSpell("Blink Strike", ret => SpellManager.HasSpell("Blink Strike") && CalculateTimeToDeath(Me.CurrentTarget) >= 1, "Blink Strike"),
                        CastSpell("Lynx Rush", ret => SpellManager.HasSpell("Lynx Rush") && CalculateTimeToDeath(Me.CurrentTarget) >= 3, "Lynx Rush"),

                        //Tier-6-Ability on cooldown. Barrage is channeled and cannot cast while moving, so only use if we stand!
                        CastSpell("Glaive Toss", ret => SpellManager.HasSpell("Glaive Toss") && CalculateTimeToDeath(Me.CurrentTarget) >= 1, "Glaive Toss"),
                        CastSpell("Powershot", ret => SpellManager.HasSpell("Powershot") && CalculateTimeToDeath(Me.CurrentTarget) >= 5, "Powershot"),
                        CastSpell("Barrage", ret => SpellManager.HasSpell("Barrage") && !Me.IsMoving && CalculateTimeToDeath(Me.CurrentTarget) >= 3, "Barrage"),

                        //===============================================================================================
                        //== Normal Attacks =============================================================================

                        //Kill Shot when target is below 20% Health.
                        CastSpell("Kill Shot", ret => Me.CurrentTarget.HealthPercent < 20, "Kill Shot"),

                        //Serpent Sting Apply once. Refresh with Cobra Shot.
                        CastSpell("Multi-Shot", ret => Me.CurrentFocus > 40, "Multi-Shot"),

                        //Explosive Shot on cooldown. Cast multiple with Lock and Load.
                        CastSpell("Explosive Shot", ret => SpellManager.HasSpell("Explosive Shot") && Me.HasAura(56453) && (!IsMyAuraActive(Me.CurrentTarget, "Explosive Shot") || MyDebuffTime("Explosive Shot", Me.CurrentTarget) < 1), "Explosive Shot"),

                        //Explosive Trap for AoE
                        new Decorator(ret => !Me.CurrentTarget.IsMoving && SpellManager.Spells["Explosive Trap"].CooldownTimeLeft.TotalSeconds < 1 && Me.CurrentTarget.InLineOfSight,
                            new PrioritySelector(
                                CastSelfSpell("Trap Launcher", ret => !Me.HasAura("Trap Launcher"), "Trap Launcher Activated"),
                                CastOnUnitLocation("Explosive Trap", ret => Me.CurrentTarget, ret => Me.HasAura("Trap Launcher"), "Explosive Trap Launched")
                            )
                        ),

                        //Ice Trap cause I glyphed the shit!
                        new Decorator(ret => SpellManager.Spells["Ice Trap"].CooldownTimeLeft.TotalSeconds < 1 && Me.CurrentTarget.InLineOfSight,
                            new PrioritySelector(
                                CastSelfSpell("Trap Launcher", ret => !Me.HasAura("Trap Launcher"), "Trap Launcher Activated"),
                                CastOnUnitLocation("Ice Trap", ret => Me.CurrentTarget, ret => Me.HasAura("Trap Launcher"), "Ice Trap Launched")
                            )
                        ),

                        //nothing else to do, cobra bugged - use steady to cast cobra...
                        CastSpell("Steady Shot", ret => (!Me.HasAura(56453) || MyDebuffTime("Explosive Shot", Me.CurrentTarget) > 1) && Me.CurrentFocus < 40, "Cobra Shot")
                        //CastSpell("Steady Shot", ret => !Me.HasAura(56453) && Me.CurrentFocus < 40, "Cobra Shot")
                    )
                )
            );
        }
        private Composite RotationNormal(CanRunDecoratorDelegate cond)
        {
            return (
                new Decorator(delegate(object a)
                {
                    if (!cond(a))
                        return false;
                    return true;
                },
                    new PrioritySelector(
                        //===============================================================================================
                        //== Cooldowns ==================================================================================

                        //Racials
                        new Decorator(ret => Me.Race == WoWRace.Troll && !SpellManager.Spells["Berserking"].Cooldown && CalculateTimeToDeath(Me.CurrentTarget) > 4,
                            new Action(delegate
                            {
                                Lua.DoString("RunMacroText('/Cast Berserking');");
                                Logging.Write(Colors.Lime, "[Racial] HULK SMASH (Berserking)");
                                return RunStatus.Failure;
                            }
                            )
                        ),
                        new Decorator(ret => Me.Race == WoWRace.Orc && !SpellManager.Spells["Blood Fury"].Cooldown && CalculateTimeToDeath(Me.CurrentTarget) > 4,
                            new Action(delegate
                            {
                                Lua.DoString("RunMacroText('/Cast Blood Fury');");
                                Logging.Write(Colors.Lime, "[Racial] HULK SMASH (Blood Fury)");
                                return RunStatus.Failure;
                            }
                            )
                        ),

                        //Trinkets
                        new Decorator(ret => varTrinket1 && Me.Inventory.Equipped.Trinket1 != null && Me.Inventory.Equipped.Trinket1.Cooldown <= 0 && Me.Inventory.Equipped.Trinket1.Usable,
                            new Action(delegate
                            {
                                Lua.DoString("RunMacroText('/use 13');");
                                {
                                    Logging.Write(Colors.Aquamarine, "[Trinket] {0}", Me.Inventory.Equipped.Trinket1.Name);
                                }
                                return RunStatus.Failure;
                            }
                            )
                        ),
                        new Decorator(ret => varTrinket2 && Me.Inventory.Equipped.Trinket2 != null && Me.Inventory.Equipped.Trinket2.Cooldown <= 0 && Me.Inventory.Equipped.Trinket2.Usable,
                            new Action(delegate
                            {
                                Lua.DoString("RunMacroText('/use 14');");
                                {
                                    Logging.Write(Colors.Aquamarine, "[Trinket] {0}", Me.Inventory.Equipped.Trinket2.Name);
                                }
                                return RunStatus.Failure;
                            }
                            )
                        ),

                        //================================================================================================
                        //== Thrill of the Hunt ==========================================================================
                        CastSpell("Arcane Shot", ret => Me.ActiveAuras.ContainsKey("Thrill of the Hunt"), "Arcane Shot (TotH)"),

                        //===============================================================================================
                        //== Tier-4-5-6 ==================================================================================

                        //Tier-4-Ability on cooldown.
                        CastSpell("Fervor", ret => SpellManager.HasSpell("Fervor") && !Me.HasAura(56453) && Me.CurrentFocus < 40 && CalculateTimeToDeath(Me.CurrentTarget) >= 4, "Fervor"),
                        CastSpell("Dire Beast", ret => SpellManager.HasSpell("Dire Beast") && !Me.HasAura(56453) && CalculateTimeToDeath(Me.CurrentTarget) >= 1, "Dire Beast"),

                        //Tier-5-Ability
                        //CastSpell("A Murder of Crows", ret => SpellManager.HasSpell("A Murder of Crows") && SpellManager.HasSpell("Fervor") && CalculateTimeToDeath(Me.CurrentTarget) >= 15, "A Murder of Crows"),
                        CastSpell("Blink Strike", ret => SpellManager.HasSpell("Blink Strike") && CalculateTimeToDeath(Me.CurrentTarget) >= 1, "Blink Strike"),
                        CastSpell("Lynx Rush", ret => SpellManager.HasSpell("Lynx Rush") && CalculateTimeToDeath(Me.CurrentTarget) >= 3, "Lynx Rush"),

                        //Tier-6-Ability on cooldown. Barrage is channeled and cannot cast while moving, so only use if we stand!
                        CastSpell("Glaive Toss", ret => SpellManager.HasSpell("Glaive Toss") && !Me.HasAura(56453) && CalculateTimeToDeath(Me.CurrentTarget) >= 1, "Glaive Toss"),
                        CastSpell("Powershot", ret => SpellManager.HasSpell("Powershot") && !Me.HasAura(56453) && CalculateTimeToDeath(Me.CurrentTarget) >= 5, "Powershot"),
                        CastSpell("Barrage", ret => SpellManager.HasSpell("Barrage") && !Me.HasAura(56453) && !Me.IsMoving && CalculateTimeToDeath(Me.CurrentTarget) >= 3, "Barrage"),

                        //===============================================================================================
                        //== Normal Attacks =============================================================================

                        //Kill Shot when target is below 20% Health.
                        CastSpell("Kill Shot", ret => Me.CurrentTarget.HealthPercent < 20, "Kill Shot"),

                        //Serpent Sting Apply once. Refresh with Cobra Shot.
                        CastSpell("Serpent Sting", ret => !Me.HasAura(56453) && CalculateTimeToDeath(Me.CurrentTarget) >= 15 && (!IsMyAuraActive(Me.CurrentTarget, "Serpent Sting") || MyDebuffTime("Serpent Sting", Me.CurrentTarget) < 2), "Serpent Sting"),

                        //Explosive Shot on cooldown. Cast multiple with Lock and Load.
                        CastSpell("Explosive Shot", ret => SpellManager.HasSpell("Explosive Shot") && (Me.CurrentFocus >= SpellManager.Spells["Explosive Shot"].PowerCost || Me.HasAura(56453)) && (!IsMyAuraActive(Me.CurrentTarget, "Explosive Shot") || MyDebuffTime("Explosive Shot", Me.CurrentTarget) < 1), "Explosive Shot"),

                        //Black Arrow on cooldown. / Explosive Trap on 4+ mobs
                        CastSpell("Black Arrow", ret => SpellManager.HasSpell("Black Arrow") && Me.CurrentFocus >= SpellManager.Spells["Black Arrow"].PowerCost && (!IsMyAuraActive(Me.CurrentTarget, "Black Arrow") || MyDebuffTime("Black Arrow", Me.CurrentTarget) < 1) && Adds < 4, "Black Arrow"),

                        //Ice Trap cause I glyphed the shit!
                        new Decorator(ret => SpellManager.Spells["Ice Trap"].CooldownTimeLeft.TotalSeconds < 1 && Me.CurrentTarget.InLineOfSight,
                            new PrioritySelector(
                                CastSelfSpell("Trap Launcher", ret => !Me.HasAura("Trap Launcher"), "Trap Launcher Activated"),
                                CastOnUnitLocation("Ice Trap", ret => Me.CurrentTarget, ret => Me.HasAura("Trap Launcher"), "Ice Trap Launched")
                            )
                        ),

                        //nothing else to do, cobra bugged - use steady to cast cobra...
                        CastSpell("Steady Shot", ret => (!Me.HasAura(56453) || MyDebuffTime("Explosive Shot", Me.CurrentTarget) > 1) && (!CanCast("Black Arrow") || Me.CurrentFocus < 35), "Cobra Shot"),
                        CastSpell("Arcane Shot", ret => !Me.HasAura(56453) && Me.CurrentFocus > (SpellManager.Spells["Black Arrow"].PowerCost + SpellManager.Spells["Explosive Shot"].PowerCost) && !CanCast("A Murder of Crows"), "Arcane Shot, Focus Dump (" + Me.CurrentFocus + ")")
                    )
                )
            );
        }
        #endregion

        #region Combat
        public override Composite CombatBehavior
        {
            get
            {
                return (
                    new PrioritySelector(
                        #region SelfControl
                        new Decorator(ret => SelfControl(Me.CurrentTarget),
                            new Action(delegate
                            {
                                Lua.DoString("StopAttack()");
                                SpellManager.StopCasting();
                                write("### Target is CrowdControled by my abilities - Stop everything! ###");
                                return RunStatus.Failure;
                            }
                            )
                        ),
                        new Decorator(ret => Me.IsChanneling || Me.IsCasting,
                            new Action(delegate
                            {
                                return RunStatus.Failure;
                            }
                            )
                        ),
                        #endregion

                        #region Valid for all Rotations1
                        new Decorator(ret => Me.GotAlivePet && Me.GotTarget && Me.Pet.CurrentTargetGuid != Me.CurrentTargetGuid && !SelfControl(Me.CurrentTarget),
                            new Action(delegate
                            {
                                Lua.DoString("PetAttack()");
                                write("[Pet] Attack my Target");
                                return RunStatus.Failure;
                            }
                            )
                        ),
                        new Decorator(ret => Me.FocusedUnit != null && Me.FocusedUnit.IsPlayer && !Me.HasAura("Misdirection") && !WoWSpell.FromId(34477).Cooldown && !SpellManager.Spells["Misdirection"].Cooldown,
                            new Action(delegate
                            {
                                Lua.DoString("RunMacroText('/cast [@focus,exists] Misdirection');");
                                Logging.Write(Colors.Aquamarine, "Misdirection on Focus");
                                return RunStatus.Failure;
                            }
                            )
                        ),
                        new Decorator(ret => TargetIsValid() && !Me.Mounted && !FeignDeath(),
                            new PrioritySelector(
                                CastSelfSpell("Mend Pet", ret => varMendPet && Me.GotAlivePet && Me.Pet.HealthPercent <= 70 && !IsMyAuraActive(Me.Pet, "Mend Pet"), "Mend Pet"),
                                CastSelfSpell("Exhilaration", ret => Me.HealthPercent < 60, "Exhilaration"),
                        #endregion

                        #region Rotationswitch
                                new PrioritySelector(
                                    RotationBoss(ret => TargetIsBoss()),
                                    RotationAdds(ret => Adds >= varAdds),
                                    RotationNormal(ret => !TargetIsBoss() && Adds < varAdds))
                        #endregion
                        
                        #region Valid for all Rotations2
                            )
                        )
                        #endregion
                    )
                );
            }
        }
        #endregion
    }
}
